package com.darren.euc.dao.impl;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.hibernate.Query;
import org.hibernate.ScrollableResults;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate4.HibernateTemplate;
import org.springframework.orm.hibernate4.SessionFactoryUtils;

import com.darren.euc.dao.BaseDao;
import com.darren.euc.entity.PageBean;

@SuppressWarnings("Duplicates")
public class BaseDaoImpl<T,PK extends Serializable> implements BaseDao<T, PK> {
	
	private Class<T> clazz;
	
	@Autowired
	protected HibernateTemplate template;
	
	@Autowired
    protected SessionFactory sessionFactory;	
	
	@SuppressWarnings("unchecked")
	public BaseDaoImpl(){
		clazz = (Class<T>)((ParameterizedType)getClass().getGenericSuperclass()).getActualTypeArguments()[0];
	}

	@Override
	public T save(T entity) {
		Session session = sessionFactory.getCurrentSession();
		session.save(entity);
		session.flush();
		return entity;
	}
	
	@Override
	public T merge(T entity) {
		Session session = sessionFactory.getCurrentSession();
		session.merge(entity);
		session.flush();
		return entity;
	}
	

	@SuppressWarnings("unchecked")
	@Override
	public T findById(PK id) {
		Session session = sessionFactory.getCurrentSession();
		return (T)session.get(clazz, id);
	}


	@Override
	public T update(T entity) {
		Session session = sessionFactory.getCurrentSession();
		session.update(entity);
		session.flush();
		return entity;
	}

	@Override
	public void delete(T entity) {
		Session session = sessionFactory.getCurrentSession();
		session.delete(entity);
	}


	protected Connection getConnection() throws SQLException {
		Connection connection = null;
		connection = SessionFactoryUtils.getDataSource(sessionFactory).getConnection();
		return connection;
	}

	@Override
	public List<Map> getDataMapList(String sql, Object... objs) {
		List list = new ArrayList();
		Connection connection = null;
		PreparedStatement pstmt=null;
		ResultSet rs=null;
		try {
			connection=getConnection();
			pstmt=connection.prepareStatement(sql);
			for(int i=0;i<objs.length;i++){
				pstmt.setObject(i+1, objs[i]);
			}
			rs=pstmt.executeQuery();
			ResultSetMetaData data = rs.getMetaData();
			while(rs.next()){
				Map map = new HashMap();
				for (int i = 0; i < data.getColumnCount(); i++) {
					map.put(data.getColumnLabel(i+1), rs.getObject(data.getColumnLabel(i+1)));
				}
				list.add(map);
			}
		} catch (SQLException e) {
			e.printStackTrace();
			
		}finally{
			try {
				connection.close();
				pstmt.close();
				rs.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}		
		return list;
	}
	
	
	@Override
	public Map<String, Object> getDataMap(String sql,Object... objs) {
		Connection connection = null;
		PreparedStatement pstmt=null;
		ResultSet rs=null;
		try {
			connection=getConnection();
			pstmt=connection.prepareStatement(sql);
			for(int i=0;i<objs.length;i++){
				pstmt.setObject(i+1, objs[i]);
			}
			rs=pstmt.executeQuery();
			while(rs.next()){
				ResultSetMetaData data = rs.getMetaData();
				Map map = new HashMap();
				for (int i = 0; i < data.getColumnCount(); i++) {
					map.put(data.getColumnLabel(i+1), rs.getObject(data.getColumnLabel(i+1)));
				}
				return map;
			}
		} catch (SQLException e) {
			e.printStackTrace();
			
		}finally{
			try {
				connection.close();
				pstmt.close();
				rs.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}		
		return null;
	}

	@Override
	public PageBean queryForPageBySQL(String sql, Integer pageSize, Integer currentPage,Object... objs) {
		Session session = sessionFactory.getCurrentSession();		
		Query query = session.createSQLQuery(sql).addEntity(clazz);
		for(int i=0;i<objs.length;i++){
			query.setParameter(i, objs[i]);
		}
		
		//得到滚动结果集
		ScrollableResults scroll = query.scroll();
		
		//滚动到最后一行
		scroll.last();
		int count = scroll.getRowNumber() + 1;
		
		//设置分页位置
		if(count >= currentPage * pageSize){			
			query.setFirstResult((currentPage - 1 ) * pageSize);
		}else{
			currentPage = count/pageSize + 1;
			query.setFirstResult(count - count % pageSize);
		}		
		query.setMaxResults(pageSize);		
		PageBean pageBean = new PageBean();
		pageBean.setPageSize(pageSize);
		pageBean.setCurrentPage(currentPage);
		pageBean.setTotalRow(count);
		pageBean.setList(query.list());
		pageBean.init();
		return pageBean;
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<T> queryByCondition(String hql,Object... objs) {
		Session session = sessionFactory.getCurrentSession();		
		Query query = session.createQuery(hql);
		for(int i=0;i<objs.length;i++){
			query.setParameter(i, objs[i]);
		}
		return query.list();
	}
	
	@Override
	public PageBean queryForPageByHQL(String hql, Integer pageSize, Integer currentPage,Object... objs) {
		Session session = sessionFactory.getCurrentSession();		
		Query query = session.createQuery(hql);
		for(int i=0;i<objs.length;i++){
			query.setParameter(i, objs[i]);
		}
		
		//得到滚动结果集
		ScrollableResults scroll = query.scroll();
		
		//滚动到最后一行
		scroll.last();
		int count = scroll.getRowNumber() + 1;
		
		//设置分页位置
		if(count >= currentPage * pageSize){			
			query.setFirstResult((currentPage - 1 ) * pageSize);
		}else{
			currentPage = count/pageSize + 1;
			query.setFirstResult(count - count % pageSize);
		}
		query.setMaxResults(pageSize);		
		PageBean pageBean = new PageBean();
		pageBean.setPageSize(pageSize);
		pageBean.setCurrentPage(currentPage);
		pageBean.setTotalRow(count);
		pageBean.setList(query.list());
		pageBean.init();
		return pageBean;
	}
}